using System;
using System.Collections.Concurrent;
using System.Threading;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.Network;

namespace OracleInternal.ServiceObjects
{
	internal class NotificationHandler
	{
		private const int NS_HEADER_SIZE = 10;

		private const int INTERRUPT_SIGNAL = -2;

		private const int NSPTCN = 1;

		private const int NSPTDA = 6;

		private int m_indexOfArraySegmentToBeRead;

		internal OracleCommunication m_dataEP;

		private ByteBuffer m_NSPacketDataBuffer = new ByteBuffer();

		private ConcurrentQueue<OraBuf> m_lstOfOraBufs;

		private ConcurrentQueue<NotificationInfo> m_lstOfNormalNotifs = new ConcurrentQueue<NotificationInfo>();

		private ConcurrentQueue<NotificationInfo> m_lstOfTimeoutNotifs = new ConcurrentQueue<NotificationInfo>();

		private bool m_bNotifSendingThreadActive;

		private bool m_bNoDataAvailInNetwork;

		internal OraBuf m_currentOB;

		private OraArraySegment[] m_lstOfArraySegments;

		private int m_lstOfArraySegments_Count;

		private ManualResetEventSlim m_dataAvailableEvnt = new ManualResetEventSlim(initialState: false);

		private ManualResetEventSlim m_dataEnqueuedEvnt = new ManualResetEventSlim(initialState: false);

		internal static NotificationBufferManager m_bufMgr = new NotificationBufferManager();

		internal NotificationHandler(OracleCommunication dataEndPoint)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ctor);
			}
			m_dataEP = dataEndPoint;
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ctor);
			}
		}

		internal void ProcessBufferedNSDataPackets()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ProcessBufferedNSDataPackets);
			}
			bool flag = true;
			try
			{
				m_indexOfArraySegmentToBeRead = 0;
				m_lstOfArraySegments_Count = 0;
				while (!m_bNoDataAvailInNetwork || flag || m_lstOfOraBufs.Count > 0)
				{
					if (!m_NSPacketDataBuffer.HasRemaining)
					{
						flag = ReadFromBufferedData();
					}
					if (flag)
					{
						UnmarshalNSDataPacket();
					}
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ProcessBufferedNSDataPackets, ex);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ProcessBufferedNSDataPackets);
				}
				if (m_currentOB != null)
				{
					m_currentOB.ReturnToPool();
					m_currentOB = null;
					m_lstOfArraySegments = null;
					m_lstOfArraySegments_Count = 0;
				}
				m_bufMgr.PutNotificationOraBufPool(m_dataEP);
				m_dataEnqueuedEvnt.Set();
			}
		}

		private void SendProcessedNotifications()
		{
			try
			{
				bool flag = false;
				while (true)
				{
					flag = false;
					NotificationInfo result;
					while (!m_lstOfTimeoutNotifs.IsEmpty)
					{
						m_lstOfTimeoutNotifs.TryDequeue(out result);
						OracleNotificationManager.s_sendNtfDetailsToUpperLayer(result);
						flag = true;
					}
					if (!m_lstOfNormalNotifs.IsEmpty)
					{
						m_lstOfNormalNotifs.TryDequeue(out result);
						OracleNotificationManager.s_sendNtfDetailsToUpperLayer(result);
						flag = true;
					}
					if (flag)
					{
						continue;
					}
					m_dataEnqueuedEvnt.Reset();
					if (m_lstOfNormalNotifs.Count == 0 && m_lstOfTimeoutNotifs.Count == 0)
					{
						m_dataEnqueuedEvnt.Wait();
						if (m_lstOfNormalNotifs.Count == 0 && m_lstOfTimeoutNotifs.Count == 0)
						{
							break;
						}
					}
					else
					{
						m_dataEnqueuedEvnt.Set();
					}
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ProcessBufferedNSDataPackets, ex);
			}
			finally
			{
				m_bNotifSendingThreadActive = false;
			}
		}

		internal void ProcessNotification()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ProcessNotification);
			}
			try
			{
				m_dataEP.Answer();
				m_dataEP.Accept(null);
				ReadFromNetwork();
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ProcessNotification, ex);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ProcessNotification);
				}
			}
		}

		internal void ReadFromNetwork()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadFromNetwork);
			}
			OraBuf oraBuf = null;
			try
			{
				m_bufMgr.GetNotificationOraBufPool(m_dataEP);
				while (true)
				{
					oraBuf = m_dataEP.OraBufPool.Get(m_dataEP.SDU, m_dataEP, bReceive: true);
					m_dataEP.m_sessionCtx.m_readerStream.Read(oraBuf, out var _, out var _);
					if (oraBuf.the_ByteSegments_Count > 0)
					{
						if (m_lstOfOraBufs == null)
						{
							m_lstOfOraBufs = new ConcurrentQueue<OraBuf>();
							m_lstOfOraBufs.Enqueue(oraBuf);
							Thread thread = new Thread(new ThreadStart(ProcessBufferedNSDataPackets));
							thread.IsBackground = true;
							thread.Start();
						}
						else
						{
							m_lstOfOraBufs.Enqueue(oraBuf);
						}
						m_dataAvailableEvnt.Set();
					}
				}
			}
			catch (NetworkException)
			{
				m_bNoDataAvailInNetwork = true;
			}
			catch (Exception ex2)
			{
				m_bNoDataAvailInNetwork = true;
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadFromNetwork, ex2);
			}
			finally
			{
				m_dataAvailableEvnt.Set();
				m_dataEnqueuedEvnt.Set();
				m_dataEP.Disconnect();
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadFromNetwork);
				}
			}
		}

		internal bool ReadFromBufferedData()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadFromBufferedData);
			}
			bool flag = false;
			try
			{
				if (m_indexOfArraySegmentToBeRead == m_lstOfArraySegments_Count)
				{
					m_lstOfArraySegments_Count = 0;
					m_indexOfArraySegmentToBeRead = 0;
					if (m_currentOB != null)
					{
						m_currentOB.ReturnToPool();
						m_currentOB = null;
						m_lstOfArraySegments = null;
						m_lstOfArraySegments_Count = 0;
					}
					if (!m_bNoDataAvailInNetwork && m_lstOfOraBufs.Count == 0)
					{
						m_dataAvailableEvnt.Reset();
						m_dataAvailableEvnt.Wait();
					}
					if (!m_lstOfOraBufs.IsEmpty)
					{
						m_lstOfOraBufs.TryDequeue(out m_currentOB);
					}
					if (m_currentOB != null)
					{
						m_lstOfArraySegments = m_currentOB.the_ByteSegments;
						m_lstOfArraySegments_Count = m_currentOB.the_ByteSegments_Count;
					}
				}
				if (m_lstOfArraySegments_Count > 0)
				{
					flag = true;
					m_NSPacketDataBuffer.m_byteBuffer = m_lstOfArraySegments[m_indexOfArraySegmentToBeRead].Array;
					m_NSPacketDataBuffer.m_position = m_lstOfArraySegments[m_indexOfArraySegmentToBeRead].Offset;
					m_NSPacketDataBuffer.m_limit = m_lstOfArraySegments[m_indexOfArraySegmentToBeRead].Count + m_lstOfArraySegments[m_indexOfArraySegmentToBeRead].Offset;
					m_indexOfArraySegmentToBeRead++;
					return flag;
				}
				return false;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadFromBufferedData, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadFromBufferedData);
				}
			}
		}

		internal void UnmarshalNSDataPacket()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.UnmarshalNSDataPacket);
			}
			try
			{
				int num = ReadShort();
				int num2 = ReadInt();
				ReadByte();
				ReadInt();
				short csId = ReadShort();
				ReadByte();
				ReadInt();
				ReadShort();
				ReadByte();
				ReadInt();
				ReadShort();
				int num3 = (num2 - 21) / 9;
				int[] array = new int[num3];
				for (int i = 0; i < num3; i++)
				{
					ReadByte();
					int num4 = ReadInt();
					byte[] array2 = new byte[num4];
					ReadBuffer(array2, 0, num4);
					for (int j = 0; j < num4; j++)
					{
						if (j < 4)
						{
							array[i] |= (array2[j] & 0xFF) << 8 * (num4 - j - 1);
						}
					}
				}
				int num5 = 2;
				byte[] array3 = null;
				if (num >= 2)
				{
					ReadShort();
					if (num5 != 2)
					{
						throw new NotSupportedException("Unsupported Unknown Namespace");
					}
					int num6 = ReadInt();
					array3 = new byte[num6];
					ReadBuffer(array3, 0, num6);
				}
				if (num >= 3)
				{
					ReadShort();
					ReadInt();
					ReadByte();
					ReadInt();
					ReadShort();
				}
				if (num > 3)
				{
					throw new Exception("Internal Error: more than 3 Handles received from DB");
				}
				if (num5 != 2)
				{
					return;
				}
				NotificationInfo item = new NotificationInfo(csId, num3, array, num >= 3, array3);
				if (num >= 3)
				{
					m_lstOfTimeoutNotifs.Enqueue(item);
				}
				else
				{
					m_lstOfNormalNotifs.Enqueue(item);
				}
				if (!m_dataEnqueuedEvnt.IsSet)
				{
					m_dataEnqueuedEvnt.Set();
				}
				if (m_bNotifSendingThreadActive)
				{
					return;
				}
				m_bNotifSendingThreadActive = true;
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.UnmarshalNSDataPacket, "(NOTIF)(New thread request)");
				}
				ThreadPool.QueueUserWorkItem(delegate
				{
					SendProcessedNotifications();
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.UnmarshalNSDataPacket, "(NOTIF)(current thread finished)");
					}
				});
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.UnmarshalNSDataPacket, ex);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.UnmarshalNSDataPacket);
				}
			}
		}

		private byte ReadByte()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadByte);
			}
			byte result = 0;
			try
			{
				if (m_NSPacketDataBuffer.HasRemaining)
				{
					result = m_NSPacketDataBuffer.GetByte();
					return result;
				}
				if (ReadFromBufferedData())
				{
					result = m_NSPacketDataBuffer.GetByte();
					return result;
				}
				return result;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadByte, ex);
				return result;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadByte);
				}
			}
		}

		private short ReadShort()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadShort);
			}
			short result = 0;
			try
			{
				if (m_NSPacketDataBuffer.Remaining >= 2)
				{
					result = m_NSPacketDataBuffer.GetShort();
					return result;
				}
				int num = ReadByte() & 0xFF;
				int num2 = ReadByte() & 0xFF;
				result = (short)(((num << 8) | num2) & 0xFFFF);
				return result;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadShort, ex);
				return result;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadShort);
				}
			}
		}

		private int ReadInt()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadInt);
			}
			int result = 0;
			try
			{
				if (m_NSPacketDataBuffer.Remaining >= 4)
				{
					result = m_NSPacketDataBuffer.GetInt();
					return result;
				}
				int num = ReadByte() & 0xFF;
				int num2 = ReadByte() & 0xFF;
				int num3 = ReadByte() & 0xFF;
				int num4 = ReadByte() & 0xFF;
				result = (num << 24) | (num2 << 16) | (num3 << 8) | num4;
				return result;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadInt, ex);
				return result;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadInt);
				}
			}
		}

		private void ReadBuffer(byte[] buff, int offset, int length)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadBuffer);
			}
			try
			{
				if (m_NSPacketDataBuffer.Remaining >= length)
				{
					m_NSPacketDataBuffer.GetBuffer(buff, offset, length);
					return;
				}
				bool flag = false;
				int num = 0;
				int num2 = 0;
				int remaining = m_NSPacketDataBuffer.Remaining;
				m_NSPacketDataBuffer.GetBuffer(buff, offset, remaining);
				offset += remaining;
				num += remaining;
				while (!flag)
				{
					remaining = m_NSPacketDataBuffer.Remaining;
					num2 = Math.Min(remaining, length - num);
					bool flag2 = true;
					if (remaining == 0)
					{
						flag2 = ReadFromBufferedData();
					}
					if (!flag2)
					{
						flag = true;
						continue;
					}
					m_NSPacketDataBuffer.GetBuffer(buff, offset, num2);
					offset += num2;
					num += num2;
					if (num == length)
					{
						flag = true;
					}
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadBuffer, ex);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationHandler, OracleTraceFuncName.ReadBuffer);
				}
			}
		}
	}
}
